﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using NHibernate;
using NHibernate.Context;
using Web7.Core.Apps;
using Web7.Core.BootStrapperTask;
using Web7.Core.IOC.Autofac;
using Web7.Core.InversionOfControl;
using Web7.Core.Security;
using Web7.Core.Security.Users;
using Web7.Core.Sites;
using Web7.Ioc;
using System.Threading;
using Web7.Dispose;
using Web7.Extensions;

namespace Web7.Core
{
    public class Web7Application : HttpApplication
    {
        private IDependencyInjector dependencyInjector;


        private static bool _isInitialised = false;
        private static Web7ApplicationStart _web7ApplicationStart;
        private static readonly ReaderWriterLockSlim InitialiserLocker = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);


        /// <summary>
        /// 初始化程序
        /// </summary>
        /// <remarks>
        /// <para>1、设置依赖关系解析器</para>
        /// <para>2、Application["bootStrappersLoaded"]，bool型；表示引导程序加载状态，
        /// 用于标识程序是否完成过初始化工作；
        /// false表示没有完成初始化工作，反之表示已经完成过。
        /// 这里将"引导程序加载状态"初始值为false。</para>
        /// <para>3、加载引导程序</para>
        /// </remarks>
        protected void Application_Start()
        {
            // UNDONE: 移除在 Application_Start 中任何对 Context 等上下文对象的访问，否则将导致应用程序无法运行在集成模式中。
            // 设置 IoC/DI 容器。用于替换ASP.NET MVC内置的依赖注入容器DefaultDependencyResolver
            
            
            
            //dependencyInjector = new DependencyResolverFactory().CreateDependencyResolver() as IDependencyInjector;
            //DependencyResolver.SetResolver(dependencyInjector as IDependencyResolver);

            //// 引导程序载入状态。当系统被首次请求时状态设置为未加载，在Load方法进行加载
            //Application["bootStrappersLoaded"] = false;

            //// 加载引导程序
            //Load(new HttpContextWrapper(Context));

            //this.EndRequest += new EventHandler(Web7Application_EndRequest);


            using (new WriteLockDisposable(InitialiserLocker))
            {
                if (_isInitialised) return;
                _web7ApplicationStart = CreateWeb7Application();
                _web7ApplicationStart.Start();
                _isInitialised = true;
            }

            // 加载引导程序
            //Load(new HttpContextWrapper(Context)); //todo:暂时注释掉


        }

        void Web7Application_EndRequest(object sender, EventArgs e)
        {
            ISessionFactory sessionFactory = dependencyInjector.GetService<ISessionFactory>();
            if (CurrentSessionContext.HasBind(sessionFactory))
            {
                ISession session = CurrentSessionContext.Unbind(sessionFactory);
                session.Flush();
                session.Close();
                session.Dispose();
            }
        }

        /// <summary>
        /// 卸载应用程序
        /// </summary>
        protected void Application_End()
        {
            if (Context != null)
                Unload(new HttpContextWrapper(Context));
        }

        protected void Application_Error(object sender, EventArgs e)
        {
            //LogException(Server.GetLastError());
        }

        private void LogException(Exception exc)
        {
            IDependencyResolver dependencyResolver = DependencyResolver.Current;
            Castle.Core.Logging.ILogger logger = dependencyResolver.GetService<Castle.Core.Logging.ILoggerFactory>().Create(typeof(Web7Application));

            HttpException httpException = exc as HttpException;
            int httpCode = 0;

            RouteData routeData = new RouteData();
            routeData.DataTokens.Add("Namespaces", "Web7.Core");
            routeData.DataTokens.Add("AppName", "Container");

            routeData.Values.Add("controller", "Error");

            if (httpException == null)
            {
                routeData.Values.Add("action", "Index");
            }
            else
            {
                httpCode = httpException.GetHttpCode();

                if (httpCode != 404)
                    logger.Error(exc.Message, exc);

                Response.Clear();

                switch (httpCode)
                {
                    case 404:
                        routeData.Values.Add("action", "HttpError404");
                        break;
                    case 500:
                        routeData.Values.Add("action", "HttpError500");
                        break;
                    default:
                        routeData.Values.Add("action", "General");
                        break;
                }
            }

            routeData.Values.Add("error", exc);

            Server.ClearError();

            IController errorController = new ErrorController();
            errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
        }

        /// <summary>
        /// 加载引导程序
        /// </summary>
        /// <param name="context">请求上下文</param>
        private static void Load(HttpContextBase context)
        {
            // 备注：实现了IBootStrapperTask接口的类，在这里称之为“引导程序”。
            // 获取所有需要加载的引导程序
            IEnumerable<IBootStrapperTask> tasks = DependencyResolver.Current.GetServices<IBootStrapperTask>();
            // 引导程序载入状态
            bool bootStrappersLoaded = _isInitialised;
            // bootStrapperState用于记录已经载入的引导程序的各种特有的状态值
            IDictionary<string, object> state = (IDictionary<string, object>)context.Application["bootStrapperState"];

            if (state == null)
            {
                context.Application["bootStrapperState"] = state = new Dictionary<string, object>();
            }

            // 如果引导程序已经执行过（比如Load方法是在运行时而不是系统首次被请求时被调用），
            // 进行相关的回滚清理工作。
            if (bootStrappersLoaded)
            {
                foreach (IBootStrapperTask task in tasks)
                {
                    task.Cleanup(state);
                }
            }

            // 启动所有引导程序
            foreach (IBootStrapperTask task in tasks)
            {
                task.Execute(state);
            }

            // 将引导程序载入状态设置为：已启动
            _isInitialised = true;
        }

        /// <summary>
        /// 卸载引导程序
        /// </summary>
        /// <remarks>用于完成一些清理工作</remarks>
        /// <param name="context">请求上下文</param>
        private static void Unload(HttpContextBase context)
        {
            if (context != null && context.Application != null)
            {
                IDictionary<string, object> state = (IDictionary<string, object>)context.Application["bootStrapperState"];

                foreach (IBootStrapperTask task in DependencyResolver.Current.GetServices<IBootStrapperTask>())
                    task.Cleanup(state);
            }
        }




       
        protected virtual void Application_EndRequest(object sender, EventArgs e)
        {
            _web7ApplicationStart.IfNotNull(x => x.OnEndRequest(sender, e));
        }

        
        protected virtual AbstractContainerBuilder CreateContainerBuilder()
        {
            return new AutofacContainerBuilder();
        }

        protected virtual Func<IWeb7DependencyResolver,IDependencyResolver> MvcResolverFactory()
        {
            return x => new AutofacMvcResolver(x);
        }

        
        protected virtual Web7ApplicationStart CreateWeb7Application()
        {
            return new Web7ApplicationStart(this, CreateContainerBuilder(), MvcResolverFactory());
        }
    }
}
